package com.android.filter;

import java.io.IOException;

import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;

import com.android.filter.jni.EffectJNI;
import com.android.filter.jni.VertexInfo;
import com.example.plasma.R;

public class GridView extends ImageView{
	public GridView(final Context context) {
		super(context);
		mContext = context;
		mPathPaint = new Paint();
		mPathPaint.setStyle(Style.STROKE);
//		mPathPaint.setARGB(90, 0, 0, 0);
		mPathPaint.setAlpha(50);
		
		mClearPaint = new Paint();
		PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
		mClearPaint.setXfermode(xfermode);
		
		mBitmapPaint = new Paint();
		mBitmapPaint.setFilterBitmap(true);
		
		mGridInfo = new GridInfo();
		try {
			mLoadingIcon = Drawable.createFromXml(context.getResources(), context.getResources().getXml(R.drawable.loading_circle));
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public GridView(final Context context,  AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		mPathPaint = new Paint();
		mPathPaint.setStyle(Style.STROKE);
		mPathPaint.setAlpha(50);
		
		mClearPaint = new Paint();
		PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
		mClearPaint.setXfermode(xfermode);
		
		mBitmapPaint = new Paint();
		mBitmapPaint.setFilterBitmap(true);
		
		mGridInfo = new GridInfo();
		try {
			mLoadingIcon = Drawable.createFromXml(context.getResources(), context.getResources().getXml(R.drawable.loading_circle));
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public GridView(final Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mContext = context;
		mPathPaint = new Paint();
		mPathPaint.setStyle(Style.STROKE);
		mPathPaint.setAlpha(50);
		
		mClearPaint = new Paint();
		PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
		mClearPaint.setXfermode(xfermode);
		
		mBitmapPaint = new Paint();
		mBitmapPaint.setFilterBitmap(true);
		
		mGridInfo = new GridInfo();
		try {
			mLoadingIcon = Drawable.createFromXml(context.getResources(), context.getResources().getXml(R.drawable.loading_circle));
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (XmlPullParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void init(final int width, final int height)
	{
		mPreviewWidth = width;
		mPreviewHeight = height;
		
		if(mGridInfo != null)
		{
			mGridInfo.freePreviewPath();
			mGridInfo.mGridType = getId();
		}
		mScaleGestureDetector = initScaleGestureDetector(mContext);
		mGesture = initGestureDetector(mContext);
		setOnTouchListener(new OnTouchListener() {
			
			public boolean onTouch(View v, MotionEvent event) {
				mScaleGestureDetector.onTouchEvent(event);
				mGesture.onTouchEvent(event);
				return true;
			}
		});
		mStartTime = System.currentTimeMillis();
		

		mRectPaint = new Paint();
		mRectPaint.setColor(Color.BLACK);
		mRectPaint.setStyle(Style.STROKE);
		mRectPaint.setStrokeWidth(2);

		new AsyncTask<Void, Integer, Path>()
		{

			@Override
			protected Path doInBackground(Void... params) {
				MosaicView mv = (MosaicView)((Activity)mContext).findViewById(R.id.mosaic_view);
				if(mv == null)
					return null;
				Bitmap input = mv.getImageBitmap();
				Path grid = null;
				if(mGridInfo != null)
				{
					mGridInfo.mVertexInfo = EffectJNI.nativeWrapMakeGrid(mGridInfo.mGridType, input);	
					grid = mGridInfo.getGridPath();
				}
				return grid;
			}
			@Override
			protected void onPostExecute(Path result)
			{
				super.onPostExecute(result);
				if(result == null)
					return;
				if(mGridInfo != null)
				{
					mGridInfo.mPreviewPath = new PreviewImage(mContext, width, height/*Bitmap.createBitmap(width, height, Config.ARGB_8888)*/);
					PreviewImage pImage = mGridInfo.mPreviewPath;
					pImage.init(mViewWidth, mViewHeight);
					pImage.setPath(result, mPathPaint);
					invalidate();
				}
//				setClickable(true);
			}
		}.execute();
		invalidate();
	}
	@Override
	public void onDraw(Canvas canvas)
	{
		if(mPreviewImage != null)
		{
			mPreviewImage.drawPreview(canvas, mBitmapPaint);
		}
		if(mGridInfo != null)
		{
			PreviewImage pImage = mGridInfo.mPreviewPath;
			if(pImage != null)
			{
//				if(mPathBitmap != null && !mPathBitmap.isRecycled())
//				{
//					mPathCanvas.drawPaint(mClearPaint);
					pImage.drawPreview(canvas, mBitmapPaint);
//					canvas.drawBitmap(mPathBitmap, 0, 0, null);
					canvas.save();
					int width = pImage.getWidth();
					int height = pImage.getHeight();
					canvas.concat(pImage.getPreviewMatrix());
					canvas.drawRect(1, 1, width-1, height-1, mRectPaint);
					canvas.restore();
//				}
			}
			else
			{
				int left = mViewWidth / 2;
				int top = mViewHeight / 2;
				
				long diff = System.currentTimeMillis() - mStartTime;
				float ratio = diff % (float)LOADING_DURATION;
				ratio = ratio / (float)LOADING_DURATION;
				int degrees = (int) (ratio * 360);
				
				if(mLoadingIcon != null )
				{
					canvas.save();
					canvas.rotate(degrees, left, top);
					
					mLoadingIcon.draw(canvas);
					canvas.restore();
				}
				invalidate();
			}
		}
		else
		{
			int left = mViewWidth / 2;
			int top = mViewHeight / 2;
			
			long diff = System.currentTimeMillis() - mStartTime;
			float ratio = diff % (float)LOADING_DURATION;
			ratio = ratio / (float)LOADING_DURATION;
			int degrees = (int) (ratio * 360);
			
			if(mLoadingIcon != null )
			{
				canvas.save();
				canvas.rotate(degrees, left, top);
				
				mLoadingIcon.draw(canvas);
				canvas.restore();
			}
			invalidate();
		}
	}
	public PreviewImage getMosaicApplyImage()
	{
		return mMosaicApplyImage;
	}
	public void destroy()
	{
		if(mPreviewImage != null)
			mPreviewImage.destroy();
		if(mGridInfo != null)
			mGridInfo.destroy();
		mLoadingIcon = null;
//		Util.recycleBitmap(mPathBitmap);
	}
	@Override
	public void onLayout(boolean changed, int left, int top, int right, int bottom)
	{
		super.onLayout(changed, left, top, right, bottom);
		if(changed)
		{
			mViewWidth = right - left;
			mViewHeight = bottom - top;
//			Util.recycleBitmap(mPathBitmap);
//			if(mPathBitmap == null)
//			{
//				int size = Math.max(mViewWidth, mViewHeight);
//				mPathBitmap = Bitmap.createBitmap(size, size, Config.ARGB_8888);
//				mPathCanvas = new Canvas(mPathBitmap);
//			}
			if(mPreviewImage != null)
				mPreviewImage.init(mViewWidth, mViewHeight);
			PreviewImage pImage = mGridInfo.mPreviewPath;
			if(pImage != null)
				pImage.init(mViewWidth, mViewHeight);
			int radius = 0;
			if(mViewWidth < mViewHeight)
				radius = mViewWidth / 20;
			else
				radius = mViewHeight / 20;
			mLoadingIcon.setBounds((mViewWidth/2) - radius, (mViewHeight/2) - radius, (mViewWidth/2) + radius, (mViewHeight/2) + radius);
		}
	}
	public int getGridType()
	{
		int ret = -1;
		if(mGridInfo != null)
			ret = mGridInfo.mGridType;
		return ret;
	}
	public GridInfo getGridInfo()
	{
		return mGridInfo;
	}
	public void setGridInfo(GridInfo gridInfo)
	{
		mGridInfo = gridInfo;
	}
	public void setNullGridInfo()
	{
		mGridInfo = null;
	}
	public PreviewImage getPreviewImage()
	{
		return mPreviewImage;
	}
	public void setNullPreviewImage()
	{
		mPreviewImage = null;
		invalidate();
	}
	public void setPreviewImage(PreviewImage preview)
	{
		mPreviewImage = preview;
		mPreviewImage.init(mViewWidth, mViewHeight);
		invalidate();
	}
	private void setTileSize(int tileSize)
	{
		MosaicView mv = (MosaicView)((Activity)mContext).findViewById(R.id.mosaic_view);
		if(mv == null)
			return ;
		Bitmap input = mv.getImageBitmap();
		PreviewImage path = null;
		Path grid = null;
		EffectJNI.nativeTileSize(tileSize);
		if(mGridInfo != null)
		{
			mMosaicApplyImage = null;
			mGridInfo.mVertexInfo = EffectJNI.nativeWrapMakeGrid(mGridInfo.mGridType, input);
			path = mGridInfo.mPreviewPath;
			grid = mGridInfo.getGridPath();
			if(path != null)
				path.setPath(grid, mPathPaint);
		}
		
		invalidate();
	}
	private ScaleGestureDetector initScaleGestureDetector(Context context)
	{
		ScaleGestureDetector ret = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {
			
			public void onScaleEnd(ScaleGestureDetector detector) {
				mOnScale = false;
				GridViewPager viewPager = (GridViewPager)((Activity)mContext).findViewById(R.id.mosaic_view_pager);
				if(mPreviewImage != null && mPreviewImage.isZoomed())
					viewPager.setSwipEnabled(false);
				else
					viewPager.setSwipEnabled(true);
			}
			
			public boolean onScaleBegin(ScaleGestureDetector detector) {
				mOnScale = true;
				GridViewPager viewPager = (GridViewPager)((Activity)mContext).findViewById(R.id.mosaic_view_pager);
				if(mPreviewImage != null && mPreviewImage.isZoomed())
					viewPager.setSwipEnabled(false);
				else
					viewPager.setSwipEnabled(true);
				return true;
			}
			
			public boolean onScale(ScaleGestureDetector detector) {
				mGridInfo.mPreviewPath.setPinchZoomScale(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), mViewWidth, mViewHeight);
				mPreviewImage.setPinchZoomScale(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), mViewWidth, mViewHeight);
				
				invalidate();
				return true;
			}
		});
		return ret;
	}
	private GestureDetector initGestureDetector(Context context)
	{
		GestureDetector ret = new GestureDetector(mContext, new OnGestureListener() {
			
			public boolean onSingleTapUp(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}
			
			public void onShowPress(MotionEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
					float distanceY) {
				if(mOnScale)
					return false;
				if(mPreviewImage.isZoomed())
				{
					mGridInfo.mPreviewPath.setTranslateX(-distanceX, -distanceY, mViewWidth, mViewHeight);
					mPreviewImage.setTranslateX(-distanceX, -distanceY, mViewWidth, mViewHeight);
					invalidate();
				}
				else
				{
					if(Math.abs(distanceX)/Math.abs(distanceY) < 0.25f)
					{
						if(distanceY < 0)
							setTileSize(mTileSize--);
						else
							setTileSize(mTileSize++);
					}
				}
				return true;
			}
			
			public void onLongPress(MotionEvent e) {
				
				new AsyncTask<Void, Void, Bitmap>()
				{
					@Override
					protected void onPreExecute()
					{
						mPreviewImage.resetPinchZoom(mViewWidth, mViewHeight);
						mGridInfo.mPreviewPath.resetPinchZoom(mViewWidth, mViewHeight);
						mGridInfo.freePreviewPath();
						invalidate();
					}
					@Override
					protected Bitmap doInBackground(Void... params) {
						Bitmap bitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888);
						if(mGridInfo != null && mGridInfo.mVertexInfo != null)
						{
							VertexInfo vInfo = mGridInfo.mVertexInfo;
							EffectJNI.nativeTileSize(mTileSize);
							EffectJNI.nativeFillColor(vInfo.num_geometric, vInfo.stride, vInfo.geometric_colors, vInfo.vertices, bitmap);
						}
						return bitmap;
					}
					@Override
					protected void onPostExecute(Bitmap result)
					{
						Bitmap bitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888);
						Canvas c = new Canvas(bitmap);
						mPreviewImage.drawBitmap(c, null);
						c.drawBitmap(result, 0, 0, null);
						mGridInfo.freePreviewPath();
						mMosaicApplyImage = mGridInfo.mPreviewPath = new PreviewImage(mContext, result.getWidth(), result.getHeight());
						PreviewImage path = mGridInfo.mPreviewPath;
						path.init(mViewWidth, mViewHeight);
						path.setBitmap(bitmap);
						result.recycle();
						result = null;
						invalidate();
						super.onPostExecute(result);
					}
				}.execute();
			}
			
			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
					float velocityY) {
				// TODO Auto-generated method stub
				return false;
			}
			
			public boolean onDown(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}
		});
		return ret;
	}
	
//	private Bitmap mPathBitmap = null;
//	private Canvas mPathCanvas = null;
	private ScaleGestureDetector mScaleGestureDetector = null;
	private GestureDetector mGesture = null;
	private int mTileSize = 15;
	private Drawable mLoadingIcon = null;
	private long mStartTime = 0;
	private final int LOADING_DURATION = 360;
	private int mViewWidth, mViewHeight;
	private int mPreviewWidth, mPreviewHeight;
	private Paint mPathPaint = null;
	private Paint mRectPaint = null;
	private Paint mClearPaint = null;
	private Paint mBitmapPaint = null;
	private PreviewImage mPreviewImage = null;
	private PreviewImage mMosaicApplyImage = null;
	private GridInfo mGridInfo = null;
	private Context mContext = null;
	private boolean mOnScale = false;
}
